package ru.chaykin;

import static ru.chaykin.load.parse.MIFParser.getRoot;

import java.math.BigDecimal;

import ru.chaykin.graphdrawers.Pen;
import ru.chaykin.load.ILoadDataProgress;
import ru.chaykin.measures.Area;
import ru.chaykin.measures.Goniometry;
import ru.chaykin.measures.Measure;
import ru.chaykin.measures.Ranging;
import ru.chaykin.menuenum.MapMenuEnum;
import ru.chaykin.primitives.Point;
import ru.chaykin.rendering.OpenGLSceneRenderer;
import ru.chaykin.util.EGLCfg;
import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class OpenGLSceneView extends GLSurfaceView implements ILoadDataProgress {
	public static final String PATH = "PATH";
	private static final long PRESSED_TIME_TRS = 75;	//Если касание длилось меньше 75 мс, то курсор будет выведен и перемещение запрещено
	
	private OpenGLSceneRenderer renderer;

	private float lastX;  
	private float lastY; // координаты последнего события
	 
	private float distance = 0; //Расстояние между пальцами при зуме
	
	private boolean firstMulti = true; // Показывает, произошло ли multitouch событие при данном вызове функции или еще при предыдущем
	private boolean pressed = false; //Показывает, а был ли пальчик ;)
	private boolean zoomTrans = false; //Транзакция зуммирования (во избежание перемещения сразу после масштабирования, когда пальцы отрываешь) 
	private boolean canMove = false;
	private MapMenuEnum mapMenuSel = MapMenuEnum.NONE;	//Определяет, какой пункт меню "Измерения" был выбран
	private long downTime = 0;
	
	private static int selObjId = OpenGLSceneRenderer.OBJECT_NOT_SELECTED;
	
	public OpenGLSceneView(Context context) {
		super(context);
		init();
	}
	
	public OpenGLSceneView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(); 
	}
	
	private void init() {
		try {
			EGLCfg.setOptimalEGLConfig(this);
	//		setEGLConfigChooser(false);
			renderer = new OpenGLSceneRenderer();
			setRenderer(renderer);
			((Activity) getContext()).setResult(Activity.RESULT_OK, ((Activity) getContext()).getIntent());
		} catch (Exception e) {
			((Activity) getContext()).finish();
		}
	}
	
	/**
	 * Обработчик касаний
	 * @see android.view.View#onTouchEvent(android.view.MotionEvent)
	 *@Override
	 */
	public boolean onTouchEvent(final MotionEvent event) {
		int PointerCount = event.getPointerCount();
		if (PointerCount > 1) 
			multiTouchZoom(event);
		else {
			firstMulti = true;
			switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN: // нажатие на экран
					lastX=event.getX();
					lastY=event.getY();
					pressed = true;
					canMove  = true;
	            break;
				case MotionEvent.ACTION_MOVE: //движение по экрану
					downTime = event.getEventTime() - event.getDownTime();
					if (canMove && !zoomTrans &&  downTime > PRESSED_TIME_TRS) { 
						renderer.move(event.getX() - lastX, event.getY() - lastY);
						pressed = false; 
						
					}
		        break;
				case MotionEvent.ACTION_UP: // отжатие
					if (canMove && !zoomTrans &&  downTime > PRESSED_TIME_TRS) {
						renderer.savePos(event.getX() - lastX, event.getY() - lastY);
						downTime = 0;
					}
					else if (pressed && !zoomTrans) 
						measure(mapMenuSel, event);
						
					pressed = false;
					canMove = false;
					zoomTrans = false;
	            break;
		        case MotionEvent.ACTION_OUTSIDE:
		        case MotionEvent.ACTION_CANCEL:
		        	pressed = false;
		        	canMove = false;
		        	zoomTrans = false;
		        break;
		        default:
		            return false; // событие не обработано
			}
		}
        return true;	// событие обработано
	}

	public void cancelMeasurement() {
		mapMenuSel = MapMenuEnum.NONE; //Отменяем всякие измерения
		Button cancelButton = (Button)((Activity)getContext()).findViewById(R.id.cancelButton);
		cancelButton.setVisibility(GONE);
		
		Button infoButton = (Button)((Activity)getContext()).findViewById(R.id.infoButton);
		if (infoButton.getVisibility() == VISIBLE) {
			infoButton.setVisibility(GONE);
			getRoot().clearSelection();
		}
		
		Activity activity = (Activity) getContext();
		TextView mesuareTextView = (TextView) activity.findViewById(R.id.mesureTextView);
		mesuareTextView.setText("");
		renderer.setMeasure(null);
	}
	//TODO При начале измерений марка должна исчезать, и подпись с координатами тоже
	
	/**
	 * Обработчик мульти касания экрана, запускает масштабирование
	 */
	private void multiTouchZoom(MotionEvent event) {
		zoomTrans = true;	//Начали транзакцию масштабирования, закончим, когда оба пальца оторвем ;)
		Point p1 = new Point(event.getX(event.getPointerId(0)), event.getY(event.getPointerId(0)));
		Point p2 = new Point(event.getX(event.getPointerId(1)), event.getY(event.getPointerId(1)));
		if (firstMulti) {
			distance = Point.distance(p1, p2);
			firstMulti = false;
		}
		else {
			float newDistance = Point.distance(p1, p2);
			float deltaZoom = newDistance - distance;
			distance = newDistance;
			renderer.zoom(deltaZoom);
		}
	}
	
	/**
	 * Выполняем действие в зависимости от того, какой пункт меню "Измерения" или "Доп. информация" был выбран
	 */
	private void measure(MapMenuEnum sel, MotionEvent event) {
		//TODO Обработать исключения, когда sel==null и т.п.
		Button cancelButton = (Button)((Activity)getContext()).findViewById(R.id.cancelButton);
		cancelButton.setVisibility(VISIBLE);
		
		Button infoButton = (Button)((Activity)getContext()).findViewById(R.id.infoButton);
		
		renderer.clearMark();
		Activity activity = (Activity) getContext();
		TextView mesuareTextView = (TextView) activity.findViewById(R.id.mesureTextView);
		
		switch ( sel ) {
			case ADDITIONAL_INFO: {
				selObjId = renderer.getSelectedObjectId(event.getX(), event.getY());
				infoButton.setVisibility(VISIBLE);
				break;
			}
			case SUB_GONIOMETRY:
				if (renderer.getMeasure() instanceof Goniometry) {
					renderer.addPointToMeasure(event.getX(), event.getY());
				}
				else {
					float radius = Float.parseFloat((String) getContext().getText(R.string.measure_radius));
					renderer.setMeasure(new Goniometry(getPenFromXml(), radius));
					renderer.zoom(0);	//Чтобы применился размер кружков. Костыль, но лучше не придумал
					renderer.addPointToMeasure(event.getX(), event.getY());
				}
				mesuareTextView.setText(Measure.getMeasuredData(renderer.getMeasure()));
			break;
			case SUB_RANGING:
				if (renderer.getMeasure() instanceof Ranging) {
					renderer.addPointToMeasure(event.getX(), event.getY());
				}
				else {
					float radius = Float.parseFloat((String) getContext().getText(R.string.measure_radius));
					renderer.setMeasure(new Ranging(getPenFromXml(), radius));
					renderer.zoom(0);	//Чтобы применился размер кружков. Костыль, но лучше не придумал
					renderer.addPointToMeasure(event.getX(), event.getY());
				}
				mesuareTextView.setText(Measure.getMeasuredData(renderer.getMeasure()));
			break;
			case SUB_AREA:
				if (renderer.getMeasure() instanceof Area) {
					renderer.addPointToMeasure(event.getX(), event.getY());
				}
				else {
					float width = Float.parseFloat((String) getContext().getText(R.string.measure_pen_width));
					int style = Integer.parseInt((String) getContext().getText(R.string.measure_pen_style));
					float radius = Float.parseFloat((String) getContext().getText(R.string.measure_radius));
					int color = getContext().getResources().getColor(R.color.measure_pen_col);
					Pen pen = new Pen(width, style, color);
					color = getContext().getResources().getColor(R.color.area_last_line_pen_col);
					renderer.setMeasure(new Area(pen, new Pen(width, style, color), radius));
					renderer.zoom(0);	//Чтобы применился размер кружков. Костыль, но лучше не придумал
					renderer.addPointToMeasure(event.getX(), event.getY());
				}
				mesuareTextView.setText(Measure.getMeasuredData(renderer.getMeasure()));
			break;
			case NONE:
				setCoordsToTextView(renderer.setPoint(event.getX(), event.getY()));
				cancelButton.setVisibility(GONE);
				infoButton.setVisibility(GONE);
			break;
		}
	}
	
	public static int getSelectedObjectId() {
		return selObjId;
		
	}
	
	private Pen getPenFromXml() {
		float width = Float.parseFloat((String) getContext().getText(R.string.measure_pen_width));
		int style = Integer.parseInt((String) getContext().getText(R.string.measure_pen_style));
		int color = getContext().getResources().getColor(R.color.measure_pen_col);
		return new Pen(width, style, color);
	}
	
	public void mapMenuSelected(MapMenuEnum sel) {
		this.mapMenuSel = sel;
	}
	
	/**
	 * Отобразить выбранные координаты на экране.
	 */
	private void setCoordsToTextView(float[] pnt) {
		Activity activity = (Activity) getContext();
		TextView coordTextView = (TextView) activity.findViewById(R.id.mesureTextView);
		BigDecimal x = new BigDecimal(pnt[0]);
		x = x.setScale(3, BigDecimal.ROUND_HALF_EVEN); /* 3 - количество знаков после запятой */
		BigDecimal y = new BigDecimal(pnt[1]);
		y = y.setScale(3, BigDecimal.ROUND_HALF_EVEN); /* 3 - количество знаков после запятой */
		coordTextView.setVisibility(VISIBLE);
		coordTextView.setText(" X = " + x.floatValue() + "	Y = " + y.floatValue() + " ");
	}

	public OpenGLSceneRenderer getRenderer() {
		return renderer;
	}

	public void onUpdate(String msg) {
		((TextView)((Activity) getContext()).findViewById(R.id.progressTextView)).setText(msg);
	}

	public void onComplete() {
		((TextView)((Activity) getContext()).findViewById(R.id.progressTextView)).setVisibility(INVISIBLE);
		Toast.makeText(getContext(), "Загрузка завершена.", Toast.LENGTH_LONG).show();
	}
}